package top.eggcode.base;

import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import top.eggcode.common.exception.ApplicationException;
import top.eggcode.common.lang.BeanUnit;

import javax.annotation.Resource;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Optional;

/**
 * Title: 带标记的通用服务
 * Description: TODO
 * Date: 2021/3/29 12:47
 *
 * @author JiaQi Ding
 * @version 1.0
 */
@Transactional(rollbackFor = Exception.class)
public abstract class BaseMarkServiceImpl<T extends BaseEntity> implements BaseService<T> {

    /**
     * 实体类的Class对象
     */
    private final Class<T> clazz;
    @Resource
    private EntityStore repository;

    @SuppressWarnings("unchecked")
    public BaseMarkServiceImpl() {
        // 获取实体类的class
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        this.clazz = ((Class<T>) type.getActualTypeArguments()[0]);
    }

    @Override
    public boolean add(T entity) {
        entity.markCreated();
        repository.add(entity);
        return true;
    }

    @Override
    public void delete(T entity) {
        repository.delete(entity);
    }

    @Override
    public void deleteById(String id) {
        get(id).ifPresent(this::delete);
    }

    public void softDelete(T entity) {
        entity.markDeleted();
        repository.update(entity);
    }


    public void softDeleteById(String id) {
        get(id).ifPresent(this::softDelete);
    }

    @Override
    public void update(T entity) {
        // 获取完整实体
        get(entity.getId()).ifPresent(aliveEntity -> {
            // 用参数的非空属性覆盖数据库实体的属性
            BeanUnit.rewrite(aliveEntity, entity);
            // 更新标记
            aliveEntity.markUpdated();
            repository.update(aliveEntity);
        });

    }

    @Override
    public void updateFull(T entity) {
        // 更新标记
        entity.markUpdated();
        repository.update(entity);
    }

    @Override
    public void put(T entity) {

        // 如果id存在
        if (StringUtils.isNotBlank(entity.getId())) {
            // 查询数据库记录
            Optional<T> box = repository.get(clazz, entity.getId());
            if (box.isPresent()) {
                this.update(entity);
            } else {
                throw new ApplicationException("id对应的数据库记录不存在");
            }
        } else {
            this.add(entity);
        }


    }

    @Override
    public List<T> find() {
        return repository.selectAll(clazz);
    }

    @Override
    public Optional<T> get(String id) {
        return repository.get(clazz, id);
    }

    @Override
    public void batchPut(List<T> entityList) {
        entityList.forEach(this::put);
    }

    @Override
    public void batchAdd(List<T> entityList) {
        entityList.forEach(this::add);
    }

    @Override
    public void flush() {
        repository.flush();
    }

    @Override
    public void refresh(T entity) {
        repository.refresh(entity);
    }

    /**
     * 必须有一条
     *
     * @param entityList 数据列表
     * @return 对象
     */
    protected T requireOne(List<T> entityList) {
        if (entityList.size() > 1) {
            throw new ApplicationException("数据疑似重复");
        } else if (entityList.size() == 0) {
            throw new ApplicationException("数据为空");
        } else {
            return entityList.get(0);
        }
    }

    /**
     * 最多有一条
     *
     * @param entityList 数据列表
     * @return 对象
     */
    protected T mostOne(List<T> entityList) {
        if (entityList.size() > 1) {
            throw new ApplicationException("需要一条记录，但是返回了多条");
        } else if (entityList.size() == 0) {
            return null;
        } else {
            return entityList.get(0);
        }
    }
}
